﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    #region Filter<T>

    sealed class Filter<T> : FunList<T>
    {
        private IFunList<T> List { get; set; }
        private FunPredicate<T> Pred { get; set; }
        private FunPredicateIdx<T> PredIdx { get; set; }
        private BoolCache<T> _filterCache = new BoolCache<T>();
        private bool _useCache = false;

        public Filter(FunPredicate<T> pred, IFunList<T> list)
        {
            List = list;
            Pred = pred;
        }

        public Filter(FunPredicateIdx<T> predIdx, IFunList<T> list)
        {
            List = list;
            PredIdx = predIdx;
        }

        #region IEnumerable<T> Members

        public override IEnumerator<T> GetEnumerator()
        {
            if (!_useCache)
            {
                if (Pred != null)
                {
                    foreach (T val in List)
                    {
                        if(Pred(val))
                        {
                            yield return val;
                        }
                    }
                }
                else if (PredIdx != null)
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if(PredIdx(val, idx))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
            }
            else
            {
                if (Pred != null)
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if (_filterCache.CacheItem(Pred, val, idx))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
                else if (PredIdx != null)
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if (_filterCache.CacheItem(PredIdx, val, idx))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
            }
        }

        #endregion
    }

    #endregion

    #region Filter2<T>

    sealed class Filter2<T> : FunList<T>
    {
        private IFunList<T> List { get; set; }
        private T Against { get; set; }
        private FunPredicate2<T> Pred { get; set; }
        private FunPredicate2Idx<T> PredIdx { get; set; }
        private BoolCache<T> _filterCache = new BoolCache<T>();
        private bool _useCache = false;

        public Filter2(FunPredicate2<T> pred, T against, IFunList<T> list)
        {
            List = list;
            Against = against;
            Pred = pred;
        }

        public Filter2(FunPredicate2Idx<T> predIdx, T against, IFunList<T> list)
        {
            List = list;
            Against = against;
            PredIdx = predIdx;
        }

        #region IEnumerable<T> Members

        public override IEnumerator<T> GetEnumerator()
        {
            if (!_useCache)
            {
                if (Pred != null)
                {
                    foreach (T val in List)
                    {
                        if(Pred(val, Against))
                        {
                            yield return val;
                        }
                    }
                }
                else
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if(PredIdx(val, idx, Against))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
            }
            else
            {
                if (Pred != null)
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if (_filterCache.CacheItem(Pred, val, idx, Against))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
                else
                {
                    int idx = 0;
                    foreach (T val in List)
                    {
                        if (_filterCache.CacheItem(PredIdx, val, idx, Against))
                        {
                            yield return val;
                        }
                        idx++;
                    }
                }
            }
        }

        #endregion
    }

    #endregion
}
